package nontermin;

import frontend.ErrorList;
import frontend.Lexer;
import frontend.Parser;
import frontend.Token;

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

public class CompUnit {

    private final ArrayList<Token> tokens ;
    private int point;
    private final ArrayList<Sign> derivation = new ArrayList<>();
    private final ErrorList errorList = ErrorList.getInstance();
    public CompUnit(ArrayList<Token> tokens) {
        this.tokens = tokens;
    }

    //CompUnit --> {Decl} {FuncDef} MainFuncDef
    public void parse() {
        NonTerminator temp;
        while (true) {
            if (isDecl()) {
                temp = declParse();
                derivation.add(temp);
            } else {
                break;
            }
        }
        while (true) {
            if (isFunDecl()) {
                temp = funcDeclParse();
                derivation.add(temp);
            } else {
                break;
            }
        }
        temp = mainFuncParse();
        derivation.add(temp);
    }


    public void output() {
        int len = derivation.size();
        try (FileWriter writer = new FileWriter("parser.txt")) {
            // 向文件中写入内容
            for (int i = 0;i < len;i++) {
                derivation.get(i).output(writer);
            }
            writer.write("<CompUnit>" + '\n');
        } catch (IOException e) {
            // 捕获并处理可能发生的IO异常
            System.out.println("An error occurred while writing to the file.");
            e.printStackTrace();
        }
    }

    public boolean isDecl() {
        return isConstDecl() || isVarDecl();
    }

    private boolean isConstDecl() {
        int res = getPoint();
        Token token = getNextToken();
        setPoint(res);
        if (token == null ) {
            return false;
        }
        return token.isEqualStr("const");
    }

    private boolean isVarDecl() {
        int res = getPoint();
        Token token1 = getNextToken();
        Token token2 = getNextToken();
        Token token3 = getNextToken();
        setPoint(res);
        if (token1 == null || token2 == null || token3 == null) {
            return false;
        }
        boolean fl1 = token1.isEqualStr("int") || token1.isEqualStr("char");
        boolean fl2 = token2.isEqualType("IDENFR");
        boolean fl3 = !token3.isEqualType("LPARENT");
        return fl1 && fl2 && fl3;
    }

    private boolean isFunDecl() {
        int res = getPoint();
        Token token1 = getNextToken();
        Token token2 = getNextToken();
        Token token3 = getNextToken();
        setPoint(res);
        if (token1 == null || token2 == null || token3 == null) {
            return false;
        }
        boolean fl1 = token1.isEqualStr("int") || token1.isEqualStr("char")
                || token1.isEqualStr("void");
        boolean fl2 = token2.isEqualType("IDENFR");
        boolean fl3 = token3.isEqualType("LPARENT");
        return fl1 && fl2 && fl3;
    }

    private boolean isFuncRParams() {
        int res = getPoint();
        Token token1 = getNextToken();
        Token token2 = getNextToken();
        setPoint(res);
        if (token1 == null || token2 == null) {
            return false;
        }
        return token1.isEqualType("IDENFR") && token2.isEqualStr("(");
    }

    private boolean isUnaryOp() {
        int res = getPoint();
        Token token = getNextToken();
        if (token == null) {
            return false;
        }
        setPoint(res);
        return token.isEqualStr("+") ||token.isEqualStr("-") || token.isEqualStr("!");
    }

    //Decl--> ConstDecl | VarDecl
    private NonTerminator declParse() {
        NonTerminator result = new NonTerminator("Decl");
        //for const
        if (isConstDecl()) {
            result.insertSig(constDeclParse());
            return result;
        }
        //for var
        if (isVarDecl()) {
            result.insertSig(varDeclParse());
            return result;
        }
        errorList.sysError("CAN NOT MATCH DECL" ,getLastLine());
        return null;
    }

    //ConstDecl --> 'const' BType ConstDef { ',' ConstDef } ';' // i
    private NonTerminator constDeclParse() {
        NonTerminator result = new NonTerminator("ConstDecl");
        Token token;
        insertToken(result,"CONSTTK");//const

        token = getNextToken();
        NonTerminator bType = new NonTerminator("BType");
        bType.insertSig(new Terminator(token));
        result.insertSig(bType);
        while (true) {
            result.insertSig(constDefParse());
            token = preNextToken();

            if (!token.isEqualStr(",")) {
                break;
            }
            insertToken(result,"COMMA");
        }

        checkError(";","i",result);
        return result;
    }

    //ConstDef --> Ident [ '[' ConstExp ']' ] '=' ConstInitVal // k
    private NonTerminator constDefParse() {
        Token token;
        NonTerminator result = new NonTerminator("ConstDef");
        insertToken(result,"IDENFR");//"identity"

        token = preNextToken();
        if (token.isEqualType("LBRACK")) {//检测[exp]
            insertToken(result);
            result.insertSig(constExpParse());
            checkError("]","k",result);
        }
        insertToken(result,"ASSIGN");//for '='
        result.insertSig(constInitParse());
        return result;
    }

    //VarDecl --> BType VarDef { ',' VarDef } ';' // i
    private NonTerminator varDeclParse() {
        NonTerminator result = new NonTerminator("VarDecl");
        Token token;
        NonTerminator temp;
        token = getNextToken();
        if (!token.isEqualStr("int") && ! token.isEqualStr("char") ) {
            errorList.sysError("NOT IDENFR IN varDecl",token.getLine());
        }
        temp = new NonTerminator("BType");
        temp.insertSig(new Terminator(token));
        result.insertSig(temp);

        while (true) {
            result.insertSig(varDefParse());
            token = preNextToken();
            if (!token.isEqualStr(",")) {
                break;
            }
            insertToken(result,"COMMA");//for ','
        }
        checkError(";","i",result);
        return result;
    }

    //VarDef --> Ident [ '[' ConstExp ']' ] | Ident [ '[' ConstExp ']' ] '=' InitVal // k
    private NonTerminator varDefParse() {
        Token token;
        NonTerminator result = new NonTerminator("VarDef");
        insertToken(result,"IDENFR");//identity

        token = preNextToken();
        if (token.isEqualType("LBRACK")) {//检测[exp]
            insertToken(result,"LBRACK");//'['
            result.insertSig(constExpParse());
            checkError("]","k",result);
        }

        token = preNextToken();
        if (!token.isEqualType("ASSIGN")) {
            return result;//选项一
        }

        insertToken(result,"ASSIGN");//for '='

        result.insertSig(initialParse());
        return result;
    }

    //FuncDef --> FuncType Ident '(' [FuncFParams] ')' Block // j
    private NonTerminator funcDeclParse() {
        NonTerminator result = new NonTerminator("FuncDef");
        Token token;
        token = getNextToken();
        NonTerminator fType = new NonTerminator("FuncType");
        fType.insertSig(new Terminator(token));
        result.insertSig(fType);
        insertToken(result,"IDENFR");//name of function
        insertToken(result,"LPARENT");//for "("
        token = preNextToken();
        if (token.isEqualStr(")")) {
            insertToken(result,"RPARENT");//")"
        } else if (token.isEqualStr("{")) {
            checkError(")","j",result);
        }
        else{
            result.insertSig(funFParasParse());
            checkError(")","j",result);
        }
        result.insertSig(blockParse());
        return result;
    }

    //FuncFParams --> FuncFParam { ',' FuncFParam }
    private NonTerminator funFParasParse() {
        NonTerminator result = new NonTerminator("FuncFParams");
        Token token;
        while (true) {
            token = preNextToken();
            if (!token.isEqualStr("int") && !token.isEqualStr("char")) {
                return result;
            }
            result.insertSig(funFParaParse());
            token = preNextToken();
            if (!token.isEqualStr(",")) {
                break;
            }
            insertToken(result,"COMMA");//for ','

        }
        return result;
    }

    //FuncFParam --> BType Ident ['[' ']'] // k
    private NonTerminator funFParaParse() {
        NonTerminator result = new NonTerminator("FuncFParam");
        Token token;
        NonTerminator temp;

        token = getNextToken();
        temp = new NonTerminator("BType");
        temp.insertSig(new Terminator(token));
        result.insertSig(temp);//for BType int|char

        insertToken(result,"IDENFR");//identity,x,y,z...

        token = preNextToken();
        if (token.isEqualStr("[")) {
            insertToken(result);
            checkError("]","k",result);
        }
        return result;
    }

    // MainFuncDef --> 'int' 'main' '(' ')' Block // j
    private NonTerminator mainFuncParse() {
        NonTerminator result = new NonTerminator("MainFuncDef");

        insertToken(result,"INTTK");//int
        insertToken(result,"MAINTK");//main
        insertToken(result,"LPARENT");//'('

        checkError(")","j",result);
        result.insertSig(blockParse());

        return result;
    }

    //ConstInitVal --> ConstExp | '{' [ ConstExp { ',' ConstExp } ] '}' | StringConst
    private NonTerminator constInitParse() {
        NonTerminator result = new NonTerminator("ConstInitVal");
        Token token = preNextToken();
        if (token.isEqualStr("{")) {
            insertToken(result);
            token = preNextToken();
            if (token.isEqualStr("}")) {
                insertToken(result);
                return result;//对于这种情况"{}"
            }
            result.insertSig(constExpParse());
            while (true) {
                token = preNextToken();
                if (token.isEqualStr(",")) {
                    insertToken(result);
                    result.insertSig(constExpParse());
                } else {
                    break;
                }
            }
            insertToken(result,"RBRACE");
            return result;
        } else if (token.isEqualType("STRCON")) {
            insertToken(result,"STRCON");
            return result;
        }
        result.insertSig(constExpParse());
        return result;
    }

    //Exp --> AddExp
    private NonTerminator expParse() {
        NonTerminator result = new NonTerminator("Exp");
        result.insertSig(addExpParse());
        return result;
    }

    //ConstExp --> AddExp
    private NonTerminator constExpParse() {
        NonTerminator result = new NonTerminator("ConstExp");
        result.insertSig(addExpParse());
        return result;
    }

    //LVal --> Ident ['[' Exp ']'] // k
    private NonTerminator lvalParse() {
        NonTerminator result = new NonTerminator("LVal");
        Token token;
        token = preNextToken();
        if (token.isEqualType("IDENFR")) {
            insertToken(result);
        } else {
            return result;
        }
        token = preNextToken();
        if(token.isEqualStr("[")) {
            insertToken(result,"LBRACK");
            result.insertSig(expParse());
            checkError("]","k",result);
        }
        return result;
    }

    //InitVal --> Exp | '{' [ Exp { ',' Exp } ] '}' | StringConst
    private NonTerminator initialParse() {
        NonTerminator result = new NonTerminator("InitVal");
        Token token = preNextToken();
        if (token.isEqualStr("{")) {
            insertToken(result,"LBRACE");
            token = preNextToken();
            if (token.isEqualStr("}")) {
                insertToken(result,"RBRACE");
                return result;//对于这种情况"{}"
            }
            result.insertSig(expParse());
            while (true) {
                token = preNextToken();
                if (token.isEqualStr(",")) {
                    insertToken(result);
                    result.insertSig(expParse());
                } else {
                    break;
                }
            }
            insertToken(result,"RBRACE");//读取'}'
            return result;
        } else if (token.isEqualType("STRCON")) {
            insertToken(result,"STRCON");
            return result;
        }
        result.insertSig(expParse());
        return result;
    }

    //Block --> '{' { BlockItem } '}'
    private NonTerminator blockParse() {
        NonTerminator result = new NonTerminator("Block");
        Token token;
        insertToken(result,"LBRACE");
        while (true) {
            token = preNextToken();
            if (token.isEqualStr("}")) {
                break;
            }
            result.insertSig(blockItemParse());
        }
        insertToken(result,"RBRACE");//for '}'
        return result;
    }

    //BlockItem --> Decl | Stmt
    private NonTerminator blockItemParse() {
        NonTerminator result = new NonTerminator("BlockItem");
        if (isDecl()) {
            result.insertSig(declParse());
            return result;
        }
        result.insertSig(stmtParse());
        return result;
    }

    /*Stmt --> LVal '=' Exp ';' // i
        | [Exp] ';' // i
        | Block
        | 'if' '(' Cond ')' Stmt [ 'else' Stmt ] // j
        | 'for' '(' [ForStmt] ';' [Cond] ';' [ForStmt] ')' Stmt
        | 'break' ';' | 'continue' ';' // i
        | 'return' [Exp] ';' // i
        | LVal '=' 'getint''('')'';' // i j
        | LVal '=' 'getchar''('')'';' // i j
        | 'printf''('StringConst {','Exp}')'';' // i j*/
    private NonTerminator stmtParse() {
        NonTerminator result = new NonTerminator("Stmt");
        Token token = preNextToken();
        /*if (times > 50) {
            System.exit(1);
        }
        System.out.println(token.toString() +" in stmt "+ token.getLine());
        times++;*/
        if (token.isEqualStr("{")) {
            result.insertSig(blockParse());
            return result;
        }
        if (token.isEqualType("IDENFR")) {
            stmtLvalParse(result);
            return result;
        }
        if (token.isEqualStr("if")) {
            stmtIfParse(result);
            return result;
        }
        if (token.isEqualStr("for")) {
            stmtForParse(result);
            return result;
        }
        if (token.isEqualStr("break") || token.isEqualStr("continue")) {
            stmtBrcParse(result);
            return result;
        }
        if (token.isEqualStr("return")) {
            stmtReturnParse(result);
            return result;
        }
        if (token.isEqualStr("printf")) {
            stmtPrintfParse(result);
            return result;
        }
        if (token.isEqualStr(";")) {
            insertToken(result,"SEMICN");
            return result;
        }
        stmtExpParse(result);
        return result;
    }

    //Stmt -->'printf''('StringConst {','Exp}')'';' // i j
    private void stmtPrintfParse(NonTerminator result) {
        Token token;
        insertToken(result,"PRINTFTK");
        insertToken(result,"LPARENT");
        insertToken(result,"STRCON");
        while (true) {
            token = getNextToken();
            if (token.isEqualStr(",")) {
                result.insertSig(new Terminator(token));
                result.insertSig(expParse());
            } else {
                setPoint(point - 1);
                break;
            }
        }
        checkError(")","j",result);
        checkError(";","i",result);
    }

    //Stmt -->'return' [Exp] ';' // i
    private void stmtReturnParse(NonTerminator result) {
        Token token;
        insertToken(result,"RETURNTK");
        token = preNextToken();
        if (token.isEqualStr(";")) {
            insertToken(result,"SEMICN");
            return;
        } else if (token.getLine() == getLastLine()){
            result.insertSig(expParse());
        }
        checkError(";","i",result);
    }

    //Stmt -->'break' ';' | 'continue' ';' // i
    private void stmtBrcParse(NonTerminator result) {
        insertToken(result);
        checkError(";","i",result);
    }

    //Stmt -->'for' '(' [ForStmt] ';' [Cond] ';' [ForStmt] ')' Stmt
    private void stmtForParse(NonTerminator result) {
        Token token;
        insertToken(result,"FORTK");
        insertToken(result,"LPARENT");

        token = preNextToken();
        if (!token.isEqualStr(";")) {
            NonTerminator temp = new NonTerminator("ForStmt");
            temp.insertSig(lvalParse());
            insertToken(temp,"ASSIGN");
            temp.insertSig(expParse());
            result.insertSig(temp);
        }
        insertToken(result,"SEMICN");

        token = preNextToken();
        if (!token.isEqualStr(";")) {
            NonTerminator temp = condParse();
            result.insertSig(temp);
        }
        insertToken(result,"SEMICN");
        token = preNextToken();
        if (!token.isEqualStr(")")) {
            NonTerminator temp = new NonTerminator("ForStmt");
            temp.insertSig(lvalParse());
            insertToken(temp,"ASSIGN");
            temp.insertSig(expParse());
            result.insertSig(temp);
        }
        insertToken(result,"RPARENT");

        result.insertSig(stmtParse());
    }

    //Stmt -->'if' '(' Cond ')' Stmt [ 'else' Stmt ] // j
    private void stmtIfParse(NonTerminator result) {
        Token token;

        insertToken(result,"IFTK");
        insertToken(result,"LPARENT");

        result.insertSig(condParse());

        checkError(")","j",result);
        result.insertSig(stmtParse());
        token = preNextToken();
        if (token.isEqualStr("else")) {
            insertToken(result,"ELSETK");
            result.insertSig(stmtParse());
        }
    }

    /*Stmt -->LVal '=' 'getint''('')'';' // i j
    | LVal '=' 'getchar''('')'';' // i j
    | LVal '=' Exp ';' // i
    | [exp] ';'  //i
     */
    private void stmtLvalParse(NonTerminator result) {
        Token token;
        int res = getPoint();
        int errorSize = errorList.getErrorSize();//需要回溯错误
        NonTerminator temp = lvalParse();
        token = preNextToken();
        if (token.isEqualStr("=")) {
            result.insertSig(temp);
            insertToken(result,"ASSIGN");
        } else {
            setPoint(res);
            errorList.resetError(errorSize);//需要回溯错误
            stmtExpParse(result);
            return;
        }

        token = preNextToken();
        if (token.isEqualStr("getint") || token.isEqualStr("getchar")) {
            insertToken(result);
            insertToken(result,"LPARENT");
            checkError(")","j",result);
            checkError(";","i",result);
            return;
        }
        result.insertSig(expParse());
        checkError(";","i",result);
    }

    //Stmt -->[exp] ';'  //i
    private void stmtExpParse(NonTerminator result) {
        Token token;
        token = preNextToken();
        if (token.isEqualStr(";")) {
            insertToken(result,"SEMICN");
            return;
        }
        result.insertSig(expParse());
        checkError(";","i",result);
    }

    //Cond --> LOrExp
    private NonTerminator condParse() {
        NonTerminator result = new NonTerminator("Cond");
        result.insertSig(lOrExpParse());
        return result;
    }

    //LOrExp --> LAndExp | LOrExp '||' LAndExp
    private NonTerminator lOrExpParse() {
        Token token;
        NonTerminator result = new NonTerminator("LOrExp");
        NonTerminator temp1;
        NonTerminator temp2;
        result.insertSig(lAndExpParse());
        while (true) {
            token = preNextToken();
            if (token.isEqualStr("||")) {
                token = getNextToken();
                temp1 = lAndExpParse();
                temp2 = new NonTerminator("LOrExp");
                temp2.insertSig(result);
                temp2.insertSig(new Terminator(token));
                temp2.insertSig(temp1);
                result = temp2;
            } else {
                break;
            }
        }
        return result;
    }

    //LAndExp → EqExp | LAndExp '&&' EqExp
    private NonTerminator lAndExpParse() {
        Token token;
        NonTerminator result = new NonTerminator("LAndExp");
        NonTerminator temp1;
        NonTerminator temp2;
        result.insertSig(eqExpParse());
        while (true) {
            token = preNextToken();
            if (token.isEqualStr("&&")) {
                token = getNextToken();
                temp1 = eqExpParse();
                temp2 = new NonTerminator("LAndExp");
                temp2.insertSig(result);
                temp2.insertSig(new Terminator(token));
                temp2.insertSig(temp1);
                result = temp2;
            } else {
                break;
            }
        }
        return result;
    }

    //EqExp --> RelExp | EqExp ('==' | '!=') RelExp
    private NonTerminator eqExpParse() {
        Token token;
        NonTerminator result = new NonTerminator("EqExp");
        NonTerminator temp1;
        NonTerminator temp2;
        result.insertSig(relExpParse());
        while (true) {
            token = preNextToken();
            if (token.isEqualStr("==")|| token.isEqualStr("!=")) {
                token = getNextToken();
                temp1 = relExpParse();
                temp2 = new NonTerminator("EqExp");
                temp2.insertSig(result);
                temp2.insertSig(new Terminator(token));
                temp2.insertSig(temp1);
                result = temp2;
            } else {
                break;
            }
        }
        return result;
    }

    //RelExp --> AddExp | RelExp ('<' | '>' | '<=' | '>=') AddExp
    private NonTerminator relExpParse() {
        Token token;
        NonTerminator result = new NonTerminator("RelExp");
        NonTerminator temp1;
        NonTerminator temp2;
        result.insertSig(addExpParse());
        while (true) {
            token = preNextToken();
            boolean fl = token.isEqualStr("<") || token.isEqualStr(">")
                    || token.isEqualStr("<=") ||token.isEqualStr(">=");
            if (fl) {
                token = getNextToken();
                temp1 = addExpParse();
                temp2 = new NonTerminator("RelExp");
                temp2.insertSig(result);
                temp2.insertSig(new Terminator(token));
                temp2.insertSig(temp1);
                result = temp2;
            } else {
                break;
            }
        }
        return result;
    }

    //AddExp --> MulExp | AddExp ('+' | '−') MulExp
    private NonTerminator addExpParse() {
        Token token;
        NonTerminator result = new NonTerminator("AddExp");
        NonTerminator temp1;
        NonTerminator temp2;
        result.insertSig(mulExpParse());
        while (true) {
            token = preNextToken();
            boolean fl = token.isEqualStr("+") || token.isEqualStr("-");
            if (fl) {
                token = getNextToken();
                temp1 = mulExpParse();
                temp2 = new NonTerminator("AddExp");
                temp2.insertSig(result);
                temp2.insertSig(new Terminator(token));
                temp2.insertSig(temp1);
                result = temp2;
            } else {
                break;
            }
        }
        return result;
    }

    //MulExp --> UnaryExp | MulExp ('*' | '/' | '%') UnaryExp
    private NonTerminator mulExpParse() {
        Token token;
        NonTerminator result = new NonTerminator("MulExp");
        NonTerminator temp1;
        NonTerminator temp2;
        result.insertSig(unaryParse());
        while (true) {
            token = preNextToken();
            boolean fl = token.isEqualStr("*") || token.isEqualStr("/")
                    || token.isEqualStr("%");
            if (fl) {
                token = getNextToken();
                temp1 = unaryParse();
                temp2 = new NonTerminator("MulExp");
                temp2.insertSig(result);
                temp2.insertSig(new Terminator(token));
                temp2.insertSig(temp1);
                result = temp2;
            } else {
                break;
            }
        }
        return result;
    }

    //UnaryExp --> PrimaryExp | Ident '(' [FuncRParams] ')' | UnaryOp UnaryExp // j
    private NonTerminator unaryParse() {
        Token token;
        NonTerminator result = new NonTerminator("UnaryExp");
        if (isUnaryOp()) {
            token = getNextToken();
            NonTerminator t = new NonTerminator("UnaryOp");
            t.insertSig(new Terminator(token));
            result.insertSig(t);
            result.insertSig(unaryParse());
            return result;
        }
        if (isFuncRParams()) {
            insertToken(result,"IDENFR");
            insertToken(result,"LPARENT");
            token = preNextToken();
            if (token.isEqualStr(")")) {
                token = getNextToken();
                result.insertSig(new Terminator(token));
            } else if (token.isEqualStr(";")||token.isEqualStr("=")){
                checkError(")","j",result);
            }else {
                result.insertSig(funcRParasParse());
                checkError(")","j",result);
            }
            return result;
        }
        result.insertSig(primaryParse());
        return result;
    }

    //PrimaryExp --> '(' Exp ')' | LVal | Number | Character// j
    private Sign primaryParse() {
        Token token;
        NonTerminator result = new NonTerminator("PrimaryExp");
        token = preNextToken();
        //System.out.println(token.toString()+"in pri");
        if (token.isEqualStr("(")) {
            insertToken(result,"LPARENT");
            result.insertSig(expParse());
            //check for ")"
            checkError(")","j",result);
            return result;
        }
        if (token.isEqualType("INTCON")) {
            token = getNextToken();
            NonTerminator t = new NonTerminator("Number");
            t.insertSig(new Terminator(token));
            result.insertSig(t);
            return result;
        }
        if (token.isEqualType("CHRCON")) {
            token = getNextToken();
            NonTerminator t = new NonTerminator("Character");
            t.insertSig(new Terminator(token));
            result.insertSig(t);
            return result;
        }
        result.insertSig(lvalParse());
        return result;
    }

    public void insertToken(NonTerminator result) {
        Token token = getNextToken();
        result.insertSig(new Terminator(token));
    }

    public void insertToken(NonTerminator result, String checkType) {
        Token token = preNextToken();
        if (token == null) {
            errorOut();
            return;
        }
        if (!token.isEqualType(checkType)) {
            System.out.println(getLastToken().toString() + " "+getLastToken().getLine());
            System.out.println("Error type : " + checkType);
            errorOut();
        }
        insertToken(result);
    }

    public void errorOut() {
        Parser parser = Parser.getInstance();
        parser.output();
        errorList.outputAll();
        System.exit(0);
    }

    public void checkError(String s, String type, NonTerminator result) {
        Token token;
        token = preNextToken();
        if (!token.isEqualStr(s)) {
            errorList.insertError(getLastLine(),type);
            token = new Token(s, Lexer.others.get(s),getLastLine());
            result.insertSig(new Terminator(token));
        } else {
            token = getNextToken();
            result.insertSig(new Terminator(token));
        }
    }

    //FuncRParams --> Exp { ',' Exp }
    private NonTerminator funcRParasParse() {
        Token token;
        NonTerminator result = new NonTerminator("FuncRParams");
        result.insertSig(expParse());
        while (true) {
            token = preNextToken();
            if (token.isEqualStr(",")) {
                token = getNextToken();
                result.insertSig(new Terminator(token));
                result.insertSig(expParse());
            } else {
                break;
            }
        }
        return result;
    }

    public Token getNextToken() {
        int res = point;
        if (res < tokens.size()) {
            point++;
            return tokens.get(res);
        } else {
            return null;
        }
    }
    public Token getLastToken() {
        int res = point - 1;
        if (res >= 0 && res < tokens.size()) {
            return tokens.get(res);
        } else {
            return null;
        }
    }
    public Token preNextToken() {
        if (point < tokens.size()) {
            return tokens.get(point);
        } else {
            return null;
        }
    }
    public int getLastLine() {
        return tokens.get(point - 1).getLine();
    }
    public  int getPoint() {
        return point;
    }
    public  void setPoint(int point) {
        this.point = point;
    }
}
